primitiveSizeLookup = 
    FLOAT : 4
    BYTE : 1
    SHORT : 2
    UNSIGNED_BYTE : 1
    UNSIGNED_SHORT : 2




class window.MeshBuffer


    constructor : (@ctx, defaultSize) ->
        @gl = @ctx.gl

        @stride = 0
        @description = []
        defaultSize ?= 10000
        @vsize = defaultSize
        @vhead = 0
        
        @isize = defaultSize
        @ihead = 0

        @verts = new Float32Array @vsize
        @idx = new Uint16Array @isize

        @idxBuff = @gl.createBuffer()
        @vertBuff = @gl.createBuffer()
        @vertexUsage = @gl.STREAM_DRAW
        @indexUsage = @gl.STREAM_DRAW


    clear : () ->
        @vhead = 0
        @ihead = 0

    addDescription : (name, type, size, normalized) ->
        normalized ?= false
        @description.push
            name   : name
            type   : @gl[type]
            size   : size
            offset : @stride 
            normalized : normalized

        @stride += size * primitiveSizeLookup[type]
    
    
    bindBuffers : () ->
        @gl.bindBuffer @gl.ARRAY_BUFFER, @vertBuff
        @gl.bindBuffer @gl.ELEMENT_ARRAY_BUFFER, @idxBuff
    
    finalize : ->
        @verts = new Float32Array @verts.subarray 0, @vhead + 1
        @idx = new Float32Array @idx.subarray 0, @ihead + 1
    
    upload : () ->    
        @bindBuffers()

        @gl.bufferData @gl.ARRAY_BUFFER, @verts, @vertexUsage
        @gl.bufferData @gl.ELEMENT_ARRAY_BUFFER, @idx, @indexUsage

    pushf : (x) ->
        @resizeVertsIfNeeded 1

        @verts[@vhead] = x
        @vhead += 1

    pushff : (x, y) ->
        @resizeVertsIfNeeded 2

        @verts[@vhead] = x
        @verts[@vhead + 1] = y
        @vhead += 2

    pushfff : (x, y, z) ->
        @resizeVertsIfNeeded 3

        @verts[@vhead] = x
        @verts[@vhead + 1] = y
        @verts[@vhead + 2] = z
        @vhead += 3

    pushffff : (x, y, z, w) ->
        @resizeVertsIfNeeded 4

        @verts[@vhead] = x
        @verts[@vhead + 1] = y
        @verts[@vhead + 2] = z
        @verts[@vhead + 3] = w
        @vhead += 4



    setup : (program) ->
        @bindBuffers()
        for desc in @description
            loc = @gl.getAttribLocation program.program, desc.name

            @gl.enableVertexAttribArray loc

            console.error "Vertex attribute #{desc.name} does not exist in shader" if loc == -1

            @gl.vertexAttribPointer loc, desc.size, desc.type, desc.normalized, @stride, desc.offset


    draw : (mode, first, count) ->
        first ?= 0
        count ?= @ihead
        mode ?= @gl.TRIANGLES

        @gl.drawElements mode, count, @gl.UNSIGNED_SHORT, first

    pushi : (x) ->
        @resizeIdxIfNeeded 1

        @idx[@ihead] = x
        @ihead += 1

    pushii : (x, y) ->
        @resizeIdxIfNeeded 2

        @idx[@ihead] = x
        @idx[@ihead + 1] = y
        @ihead += 2


    pushiii : (x, y, z) ->
        @resizeIdxIfNeeded 3

        @idx[@ihead] = x
        @idx[@ihead + 1] = y
        @idx[@ihead + 2] = z
        @ihead += 3

    resizeVertsIfNeeded : (size) ->
        if @vsize > @vhead + size
            return false
        
        console.log "resizing vertices"

        newSize = @vsize + @vsize / 2
        newBuff = new Float32Array newSize
        newBuff.set @verts
        @verts = newBuff
        @vsize = newSize


    resizeIdxIfNeeded : (size) ->
        if @isize > @ihead + size
            return false
        
        console.log "resizing index"
        newSize = @isize + @isize / 2
        newBuff = new Uint16Array newSize
        newBuff.set @idx
        @idx = newBuff
        @isize = newSize
